#include "StringNumber.hpp"
#include <iostream>

StringNumber::StringNumber(std::string s):
	word(s)
{
	parse();
}

StringNumber::StringNumber():
	word("zero")
{
	parse();
}

bool StringNumber::parse()
{
	std::string tempWord = word;
	integer = toIntegerOperation(tempWord);
	if ( integer == -1 )
	{
		word = "INVALID";
		roman = "INVALID";
		return false;
	}
	roman = toRomanNumeralOperation();

	return true;
}

bool StringNumber::startState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	if (tokenMap[currentToken] == WordList::ZERO ||
		(tokenMap[currentToken] >= WordList::TEN &&
		tokenMap[currentToken] <= WordList::NINETEEN) )
	{
		integer+=valueMap[currentToken];
		return terminalState(s, tokenMap, valueMap);
	}
	else if ( tokenMap[currentToken] >= WordList::ONE &&
			tokenMap[currentToken] <= WordList::NINE )
	{
		return oneToNineState(s, tokenMap, valueMap);
	}
	else if ( tokenMap[currentToken] >= WordList::TWENTY &&
			tokenMap[currentToken] <= WordList::NINETY )
	{
		integer += valueMap[currentToken];
		return twentyToNinetyState(s, tokenMap, valueMap);
	}
	else
	{
		integer = -1;
		return false;
	}
	return false;
}

bool StringNumber::terminalState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	previousToken = currentToken;
	currentToken = tokenize(s);

	if ( tokenMap[currentToken] == WordList::END )
	{
		return true;
	}
	else
	{
		integer = -1;
		return false;
	}
}

bool StringNumber::oneToNineState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	previousToken = currentToken;
	currentToken = tokenize(s);

	if ( tokenMap[currentToken] == WordList::END )
	{
		integer+=(valueMap[previousToken]);
		return true;
	}
	else if ( tokenMap[currentToken] == WordList::HUNDRED )
	{
		integer += (valueMap[previousToken] * 100);
		return hundredState(s, tokenMap, valueMap);
	}
	else if ( previousToken == "one" && tokenMap[currentToken] == WordList::THOUSAND )
	{
		integer += (valueMap[previousToken] * 1000);
		return thousandState(s, tokenMap, valueMap);
	}
	else
	{
		integer = -1;
		return false;
	}
}

bool StringNumber::twentyToNinetyState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	previousToken = currentToken;
	currentToken = tokenize(s);

	if ( tokenMap[currentToken] == WordList::END )
	{
		return true;
	}
	else if ( tokenMap[currentToken] >= WordList::ONE &&
			tokenMap[currentToken] <= WordList::NINE )
	{
		integer += valueMap[currentToken];
		return terminalState(s, tokenMap, valueMap);
	}
	else
	{
		integer = -1;
		return false;
	}
}

bool StringNumber::hundredState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	previousToken = currentToken;
	currentToken = tokenize(s);

	if ( tokenMap[currentToken] == WordList::END )
	{
		return true;
	}
	else if ( tokenMap[currentToken] >= WordList::ONE &&
			tokenMap[currentToken] <= WordList::NINETEEN )
	{
		integer += valueMap[currentToken];
		return terminalState(s, tokenMap, valueMap);
	}
	else if ( tokenMap[currentToken] >= WordList::TWENTY &&
			tokenMap[currentToken] <= WordList::NINETY )
	{
		integer += valueMap[currentToken];
		return twentyToNinetyState(s, tokenMap, valueMap);
	}

	else
	{
		integer = -1;
		return false;
	}
}

bool StringNumber::thousandState(std::string &s, WordtoTokenMap tokenMap, WordtoValueMap valueMap)
{
	previousToken = currentToken;
	currentToken = tokenize(s);

	if (tokenMap[currentToken] == WordList::END )
	{
		return true;
	}
	else
	{
		integer = -1;
		return false;
	}
}

int StringNumber::toIntegerOperation(std:: string s)
{
	WordtoTokenMap wordTokenMap = WordList::generateWordTokenMap();
	WordtoValueMap wordValueMap = WordList::generateWordValueMap();
	integer = 0;
	currentToken = tokenize(s);

	if (!startState(s, wordTokenMap, wordValueMap))
		return -1;
	else
		return integer;
}

std::string StringNumber::toRomanNumeralOperation()
{
	Integer i(integer);
	return i.toRomanNumeral();
}

int StringNumber::toInteger() const
{
	return integer;
}

std::string StringNumber::toRomanNumeral() const
{
	return roman;
}

std::string StringNumber::toWordNumber() const
{
	return word;
}

std::string StringNumber::tokenize(std::string &s)
{
	std::string subS = "";

	int pos = s.find(' ');

	if ( pos != std::string::npos )
	{
		if ( pos == s.length()-1 )
		{
			subS = s.substr(0,pos);
			s = "";
		}
		else
		{
			subS = s.substr(0,pos);
			s = s.substr(pos+1,s.length()-1);
		}
	}
	else
	{
		subS = s;
		s = "";
	}
	std::vector<std::string> wordList = WordList::generateWordList();

	for ( int i = 0; i < WORDSCOUNT; i++ )
	{
		if ( subS == wordList[i] )
			return subS;
	}

	return "INVALID";
}

std::string StringNumber::operator+ (const StringNumber& a) const{

	if (a.word == "INVALID" || word == "INVALID")
		return "INVALID";

	Integer intresult = integer + a.integer;
	if (intresult.toInteger() == -1)
		return "INVALID";


	std::string result = intresult.toWordNumber();


	return result;
}
std::string StringNumber::operator- (const StringNumber& a) const{

	if (a.word == "INVALID" || word == "INVALID")
		return "INVALID";

	Integer intresult = integer - a.integer;
	if (intresult.toInteger() == -1)
		return "INVALID";

	std::string result = intresult.toWordNumber();

	return result;
}
std::string StringNumber::operator* (const StringNumber& a) const{
	if (a.word == "INVALID" || word == "INVALID")
		return "INVALID";

	Integer intresult = integer * a.integer;
	if (intresult.toInteger() == -1)
		return "INVALID";

	std::string result = intresult.toWordNumber();


	return result;
}
std::string StringNumber::operator/ (const StringNumber& a) const{
	if (a.word == "INVALID" || word == "INVALID" || a.word == "ZERO")
		return "INVALID";

	Integer intresult = integer / a.integer;
	if (intresult.toInteger() == -1)
		return "INVALID";

	std::string result = intresult.toWordNumber();


	return result;
}
std::string StringNumber::operator% (const StringNumber& a) const{
	if (a.word == "INVALID" || word == "INVALID")
		return "INVALID";

	Integer intresult = integer % a.integer;
	if (intresult.toInteger() == -1)
		return "INVALID";

	std::string result = intresult.toWordNumber();


	return result;
}

bool StringNumber::operator>(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer > rhs.integer;
}
bool StringNumber::operator<(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer < rhs.integer;
}
bool StringNumber::operator>=(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer >= rhs.integer;
}
bool StringNumber::operator<=(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer <= rhs.integer;
}
bool StringNumber::operator==(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	return lhs.integer == rhs.integer;
}
bool StringNumber::operator!=(const StringNumber& rhs) const
{
	StringNumber lhs = *this;
	return lhs.integer != rhs.integer;
}
